//*************************************************************************************
// EGTB Generator Retrograde Algorithm
//*************************************************************************************

#include "Retrograde.h"

// header containing templated functions
namespace EndGameDB
{
	
	// SetDbToUNKNOWN - clears the raw database slices for computing
	////////////////////////////////////////////////////////////////////////////////////////////////////////////
	
	template<int BitsPerRow, int MaxField>
	void SetDbToUNKNOWN(uint32 *currentdb_w, uint32 *currentdb_b, uint8* dtm_w, uint8* dtm_b, 
							int wm, int wk, int bm, int bk, int wmrank, int bmrank)
	{
	
		bool symmetric = IsSymmetric(bm, bk, wm, wk, bmrank, wmrank);
		int64 memsize = GetDatabaseSize<BitsPerRow, MaxField>(wm, wk, bm, bk, wmrank, bmrank);
		int64 dbsize = Pad16(memsize / 4);

		memset(currentdb_w, 0, (size_t)dbsize);
		memset(dtm_w, 0, (size_t)memsize);
		if(!symmetric)
		{
			memset(currentdb_b, 0, (size_t)dbsize);
			memset(dtm_b, 0, (size_t)memsize);
		}
	}


	 // SET IMPOSSIBLE TO - clearing impossible positions
	////////////////////////////////////////////////////////////////////////////////////////////////////////////

	template<typename BB, int MaxRank, int BitsPerRow, int MaxField> 
	void SetImpossibleTo(int wm, int wk, int bm, int bk, int wmrank, int bmrank, 
							  uint32 *currentdb_w, uint32 *currentdb_b, uint8* dtm_w, uint8* dtm_b, int result)
	{
		int64 index;
		bool symmetric = IsSymmetric(wm, wk, bm, bk, wmrank, bmrank);
		int64 dbsize = GetDatabaseSize<BitsPerRow, MaxField>(wm, wk, bm, bk, wmrank, bmrank);
		BB p; 

	
		if(bmrank+wmrank>MaxRank)
		{
			for(index=0; index<dbsize; index++)
			{
				IndexToBitBoardXX<BB>(index, &p, wm, wk, bm, bk, wmrank, bmrank);
				if(p.bm & p.wm)
				{
					SetDatabaseValue(currentdb_w, index, result);
					SetDTMValue(dtm_w, index, 0);

					if (!symmetric)
					{
						SetDatabaseValue(currentdb_b, index, result);
						SetDTMValue(dtm_b, index, 0);
					}
				}
			}
		}
	}


	 // RESOLVE CAPTURES - fills in the db slice the captures
	////////////////////////////////////////////////////////////////////////////////////////////////
	
	template<typename BB, int MaxField, int BitsPerRow> 
	void ResolveCaptures(int wm, int wk, int bm, int bk, int wmrank, int bmrank, 
						uint32 *currentdb_w, uint32 *currentdb_b, uint8* dtm_w, uint8* dtm_b)
	{
		int j;
		register int64 index;
		int64 dbsize = GetDatabaseSize<BitsPerRow, MaxField>(wm, wk, bm, bk, wmrank, bmrank);
		bool symmetric = IsSymmetric(wm, wk, bm, bk, wmrank, bmrank);
		int bestvalue;
		int value;
		int64 nodes = 0;

		//int logId = -1;
		//if(wk == 3 && bk == 1)
		//	logId = LogInit("c:\\resolvecaptures.log");

		PROGRESS_DECLARE();
		PROGRESS_INIT(5, dbsize);

		PRINT(L"WHITE");

		int win = 0;
		int loss = 0;
		int draw = 0;
		int nonjump = 0;

		BB p;

		DECLARE_TERMINATE_PARALLEL();
	
		#pragma omp parallel default(none) shared(dbsize, wm, wk, bm, bk, wmrank, bmrank, currentdb_w, dtm_w, PROGRESS_PARALLEL(), nodes, TERMINATE_PARALLEL(), DECLARE_MEMORY_PANIC()) private(bestvalue, value, index, p, j)
		{
			BB *bitMoves = new BB[MAX_MOVES];

			#pragma omp for schedule(dynamic, 1000)
			for (index=0;index<dbsize;index++)
			{
				#pragma omp flush (TERMINATE_PARALLEL())
				IS_NOT_TERMINATE()
				{
					/*char sz[1000];
					sprintf(sz, "ResolveCaptures - index:[%I64d/%I64d]", index, dbsize);
					LogMessage(iGeneratorLog, sz);

					if(index == 3332)
					{
						int jjjj = 1;
					}*/


					if( (nodes & 0x3FF) == 0)
					{
						CHECK_TERMINATE_PARALLEL();
						#pragma omp flush (TERMINATE_PARALLEL())
					}

					#pragma omp atomic
					nodes++;
					PROGRESS_CHECK(nodes)
					{
						#pragma omp critical
						{
							PROGRESS_WORK(nodes);
						}
					}


					IndexToBitBoardXX<BB>(index, &p, wm, wk, bm, bk, wmrank, bmrank);

					// check for impossible BitBoards
					if(p.bm & p.wm)
						continue;

		
					if(TestJump<BB>(g_ED, &p, true))
					{
						int count = MoveGenerator<BB>(g_ED, &p, true, bitMoves);

						//if(logId >= 0)
						//	LogBB(logId, p);

						bestvalue = LOSS;
						uint8 bestDtmWin = 255;
						uint8 bestDtmLoss = 0;
						uint8 dtmValue = 0;
						for(j=0; j<count; j++)
						{
							ToggleMove<BB>(&p, &bitMoves[j]);
							value = Lookup<BB, MaxField, BitsPerRow, true>(&p, BLACK, &dtmValue);
							ToggleMove<BB>(&p, &bitMoves[j]);
		
							if(value == LOSS)
							{
								bestvalue = WIN;

								// searching for fastest win
								if(bestDtmWin > dtmValue)
									bestDtmWin = dtmValue;
							}
							if(value == DRAW && bestvalue != WIN)
							{
								bestDtmWin = 70;
								bestvalue=DRAW;
							}
							if(value == WIN && (bestvalue != DRAW && bestvalue != WIN))
							{
								if(bestDtmLoss < dtmValue)
									bestDtmLoss = dtmValue;
							}
							if(value == UNKNOWN && bestvalue != WIN)
							{
								bestvalue = UNKNOWN;
								dtmValue = 0;
							}
						}

						dtmValue = bestvalue == LOSS ? bestDtmLoss : bestDtmWin;

						if(count == 0)
							dtmValue = 0;
						if(bestvalue == DRAW || bestvalue == UNKNOWN)
							dtmValue = 0;

						SetDatabaseValue(currentdb_w, index, bestvalue);
						SetDTMValue(dtm_w, index, dtmValue + 1);
						// SetDTMValue(dtm_w, index, 0);
					}
				}

				IS_MEMORY_PANIC()
				{
					#pragma omp atomic
					countThreadSleep++;
					#pragma omp flush(countThreadSleep)
				
					omp_set_lock(&lockMemoryPanic);
					omp_unset_lock(&lockMemoryPanic);
				}
			}

			delete[] bitMoves;
		}

		TERMINATE_RAISE_EXCEPTION();


		if(!symmetric)
		{
			PROGRESS_INIT(5, dbsize);
			PRINT(L"BLACK");

			nodes = 0;

			#pragma omp parallel default(none) shared(DECLARE_MEMORY_PANIC(), dbsize, wm, wk, bm, bk, wmrank, bmrank, currentdb_b, dtm_b, PROGRESS_PARALLEL(), nodes, TERMINATE_PARALLEL()) private(bestvalue, value, index, p, j)
			{
				BB *bitMoves = new BB[MAX_MOVES];

				#pragma omp for schedule(dynamic, 1000)
				for(index=0; index<dbsize; index++)
				{
					#pragma omp flush (TERMINATE_PARALLEL())				
					IS_NOT_TERMINATE()
					{
						if( (nodes & 0x3FF) == 0)
						{
							CHECK_TERMINATE_PARALLEL();
							#pragma omp flush(TERMINATE_PARALLEL())
						}

						#pragma omp atomic
						nodes++;
						PROGRESS_CHECK(nodes)
						{
							#pragma omp critical
							{
								PROGRESS_WORK(nodes);
							}
						}

						IndexToBitBoardXX<BB>(index, &p, wm, wk, bm, bk, wmrank, bmrank);
			
						// collision detection
						if(p.bm & p.wm)
							continue;

						if(TestJump<BB>(g_ED, &p, false))
						{

							//if(logId >= 0)
							//{
							//	LogBB(logId, p);
							//}

							int count = MoveGenerator<BB>(g_ED, &p, false, bitMoves);

							bestvalue = LOSS;
							uint8 bestDtmWin = 255;
							uint8 bestDtmLoss = 0;
							uint8 dtmValue = 0;
							for(j=0; j<count; j++)
							{				
								ToggleMove<BB>(&p, &bitMoves[j]);
								value = Lookup<BB, MaxField, BitsPerRow, true>(&p, WHITE, &dtmValue);
								ToggleMove<BB>(&p, &bitMoves[j]);
	
								if(value == LOSS)
								{
									bestvalue = WIN;
								// searching for fastest win
									if(bestDtmWin > dtmValue)
										bestDtmWin = dtmValue;
								}					
								if(value == DRAW && bestvalue != WIN)
								{						
									bestDtmWin = 70;
									bestvalue=DRAW;
								}
								if(value == WIN && (bestvalue != DRAW && bestvalue != WIN))
								{
									if(bestDtmLoss < dtmValue)
										bestDtmLoss = dtmValue;
								}
								if(value == UNKNOWN && bestvalue != WIN)
								{
									bestvalue = UNKNOWN;
									dtmValue = 0;
								}
							}
	
							dtmValue = bestvalue == LOSS ? bestDtmLoss : bestDtmWin;

							//if(logId >= 0)
							//{
							//	char sBestValue[10];
							//	strcpy_s(sBestValue, 10, "UNKNOWN");
							//	switch(bestvalue)
							//	{
							//	case WIN:
							//		win++;
							//		strcpy_s(sBestValue, "WIN");
							//		break;
							//	case LOSS:
							//		loss++;
							//		strcpy_s(sBestValue, "LOSS");
							//		break;
							//	case DRAW:
							//		draw++;
							//		strcpy_s(sBestValue, "DRAW");
							//		break;
							//	}

							//	LOG_MSG(logId, "Value: %s, DTM: %d\n", sBestValue, dtmValue);
							//}


							if(count == 0)
								dtmValue = 0;
							if(bestvalue == DRAW || bestvalue == UNKNOWN)
								dtmValue = 0;
			
							SetDatabaseValue(currentdb_b, index, bestvalue);
							// SetDTMValue(dtm_b, index, 0);
							SetDTMValue(dtm_b, index, dtmValue + 1);
						}
						//else nonjump++;

						IS_MEMORY_PANIC()
						{
							#pragma omp atomic
							countThreadSleep++;
							#pragma omp flush(countThreadSleep)
				
							omp_set_lock(&lockMemoryPanic);
							omp_unset_lock(&lockMemoryPanic);
						}
					}
				}
			delete[] bitMoves;

			}

			TERMINATE_RAISE_EXCEPTION();
		}

		//if(logId >= 0)
		//{
		//	LOG_MSG(logId, "Win %d, Loss: %d, Draw: %d, NonJump: %d", win, loss, draw, nonjump);
		//	LogClose(logId);
		//}
	}


	 // IOPassWhite - passing white men to conversion
	////////////////////////////////////////////////////////////////////////////////////////////////
	template<typename BB, int MaxField, int BitsPerRow> 
	void IOPassWhite(uint32 *currentdb, uint8* dtm,int wm, int wk, int bm, int bk, int wmrank, int bmrank)
	{
		int64 dbsize = GetDatabaseSize<BitsPerRow, MaxField>(wm, wk, bm, bk, wmrank, bmrank);
		bool symmetric = IsSymmetric(wm, wk, bm, bk, wmrank, bmrank);
		int64 i;
		uint32 value, bestvalue;
		BB p;
		int n, conv;
		int conversion;

		PROGRESS_DECLARE();
		PROGRESS_INIT(5, dbsize);
		int64 nodes = 0;

		DECLARE_TERMINATE_PARALLEL();

	
		#pragma omp parallel default(none) shared(DECLARE_MEMORY_PANIC(), dbsize, wm, wk, bm, bk, wmrank, bmrank, currentdb, dtm, PROGRESS_PARALLEL(), nodes, TERMINATE_PARALLEL()) private(bestvalue, value, i, p, n, conv, conversion)
		{
			BB* bitMoves = new BB[MAX_MOVES];

			#pragma omp for schedule(dynamic, 1000)
			for(i=0; i<dbsize; i++)
			{
				#pragma omp flush(TERMINATE_PARALLEL())
				IS_NOT_TERMINATE()
				{

					if( (nodes & 0x3FF) == 0)
					{
						CHECK_TERMINATE_PARALLEL();
						#pragma omp flush(TERMINATE_PARALLEL())
					}

					#pragma omp atomic
					nodes++;
					PROGRESS_CHECK(nodes)
					{
						#pragma omp critical
						{
							PROGRESS_WORK(nodes);
						}
					}


					if(GetDatabaseValue(currentdb, i) == UNKNOWN)
					{
						IndexToBitBoardXX<BB>(i, &p, wm, wk, bm, bk, wmrank, bmrank);

						// collision detection
						if(p.bm & p.wm)
							continue;
			
						bestvalue = LOSS;

						if(TestJump<BB>(g_ED, &p, true))
							continue;

						// make a movelist
						n = MoveGenerator<BB>(g_ED, &p, true, bitMoves);
			

						conv = 0;
						uint8 bestDtmWin = 255;
						uint8 bestDtmLoss = 0;
						uint8 dtmValue = 0;
						// look up all successors and propagate their values
						for(int j=0; j<n; j++)
						{
							BB resP;

							ToggleMove<BB>(&p, &bitMoves[j]);
							resP = p;			
							ToggleMove<BB>(&p, &bitMoves[j]);

							// if ! conversion continue
							conversion = 0;
							if(resP.wm)
							{
								if( MSBxx<BB>(resP.wm)/BitsPerRow > wmrank)
									conversion = 1;
							}
							if( BitCountXX<BB>(resP.wk) > BitCountXX<BB>(p.wk))
								conversion = 1;

			
							if(!conversion)
							{
								continue;
							}

							conv++;
				
							value = Lookup<BB, MaxField, BitsPerRow, true>(&resP, BLACK, &dtmValue);

							if(value == LOSS)
							{
								if(bestvalue != WIN)
									bestDtmWin = dtmValue;

								bestvalue = WIN;							
								if(bestDtmWin > dtmValue)
									bestDtmWin = dtmValue;
							}

							if(value == DRAW && bestvalue != WIN)
							{
								bestDtmWin = 70;
								bestvalue=DRAW;
							}
							if(value == WIN && (bestvalue != DRAW && bestvalue != WIN))
							{
								if(bestDtmLoss < dtmValue)
									bestDtmLoss = dtmValue;
							}
						}



						// change the next statement to = WIN in case of suicide checkers
						if(n == 0)
							bestvalue = LOSS;

						dtmValue = bestvalue == LOSS ? bestDtmLoss : bestDtmWin;

						if(n == 0)
							dtmValue = 0;

						// set value in case it's a win or if all successors are known:
						if(conv == n && bestvalue == LOSS)
						{
							SetDatabaseValue(currentdb, i, LOSS);
							SetDTMValue(dtm, i, dtmValue + 1);
							// SetDTMValue(dtm, i, 0);
						}
						else if(bestvalue!=LOSS)
						{
							SetDatabaseValue(currentdb, i, bestvalue);
							SetDTMValue(dtm, i, dtmValue + 1);
							// SetDTMValue(dtm, i, 0);
						}
					}
					IS_MEMORY_PANIC()
					{
						#pragma omp atomic
						countThreadSleep++;
						#pragma omp flush(countThreadSleep)
				
						omp_set_lock(&lockMemoryPanic);
						omp_unset_lock(&lockMemoryPanic);
					}

				}
			}

			delete[] bitMoves;
		}

		TERMINATE_RAISE_EXCEPTION();
	}


	 // IOPassBlack - passing black men to conversion
	////////////////////////////////////////////////////////////////////////////////////////////////

	template<typename BB, int MaxField, int BitsPerRow> 
	void IOPassBlack(uint32 *currentdb, uint8* dtm, int wm, int wk, int bm, int bk, int wmrank, int bmrank)
	{
		int64 dbsize = GetDatabaseSize<BitsPerRow, MaxField>(wm, wk, bm, bk, wmrank, bmrank);
		bool symmetric = IsSymmetric(wm, wk, bm, bk, wmrank, bmrank);
		int64 i;
		int j;
		int value, bestvalue;
		BB p;
		int n, conv;
		int conversion;
		int64 nodes = 0;

		PROGRESS_DECLARE();
		PROGRESS_INIT(5, dbsize);
		DECLARE_TERMINATE_PARALLEL();

	
		#pragma omp parallel default(none) shared(DECLARE_MEMORY_PANIC(), dbsize, wm, wk, bm, bk, wmrank, bmrank, currentdb, dtm, PROGRESS_PARALLEL(), nodes, TERMINATE_PARALLEL()) private(bestvalue, value, i, p, n, conv, conversion, j)
		{
			BB *bitMoves = new BB[MAX_MOVES];

			#pragma omp for schedule(dynamic, 1000)
			for(i=0; i<dbsize; i++)
			{
				#pragma omp flush(TERMINATE_PARALLEL())
				IS_NOT_TERMINATE()
				{

					if( (nodes & 0x3FF) == 0)
					{
						CHECK_TERMINATE_PARALLEL();
						#pragma omp flush(TERMINATE_PARALLEL())
					}

					#pragma omp atomic
					nodes++;
					PROGRESS_CHECK(nodes)
					{
						#pragma omp critical
						{
							PROGRESS_WORK(nodes);
						}
					}

					if(GetDatabaseValue(currentdb, i) == UNKNOWN)
					{
						conv = 0;
						bestvalue = LOSS;
			
						IndexToBitBoardXX<BB>(i, &p, wm, wk, bm, bk, wmrank, bmrank);

						// collision detection
						if(p.bm & p.wm)
							continue;


						// ignore jumps
						if(TestJump<BB>(g_ED, &p, false))
							continue;

						// make a movelist
						n = MoveGenerator<BB>(g_ED, &p, false, bitMoves);	

						// look up all successors and propagate their values
						uint8 bestDtmWin = 255;
						uint8 bestDtmLoss = 0;
						uint8 dtmValue = 0;
						for(j=0; j<n; j++)
						{
							// if ! conversion continue
							conversion = 0;

							BB resP;

							ToggleMove<BB>(&p, &bitMoves[j]);
							resP = p;
							ToggleMove<BB>(&p, &bitMoves[j]);

							//-----------------------------------------------------------------------------------------------------
							// tricky!! if movelist[j].wm was 0, then this expression
							// for the rank computation is wrong, as LSB returns -1, giving 
							// 32/4 = 8 > wmrank always!
							//-----------------------------------------------------------------------------------------------------
							if(resP.bm)
							{
								if( (MaxField-LSBxx<BB>(resP.bm))/BitsPerRow > bmrank)
									conversion = 1;
							}
							if(BitCountXX<BB>(resP.bk) > BitCountXX<BB>(p.bk)) 
								conversion = 1;


							if(!conversion)
								continue;
				
							conv++;

							value = Lookup<BB, MaxField, BitsPerRow, true>(&resP, WHITE, &dtmValue);

							if(value == LOSS)
							{
								if(bestvalue != WIN)
									bestDtmWin = dtmValue;

								bestvalue = WIN;
								if(bestDtmWin > dtmValue)
									bestDtmWin = dtmValue;
							}
							if(value == DRAW && bestvalue != WIN)
							{
								bestDtmWin = 70;
								bestvalue=DRAW;
							}
							if(value == WIN && (bestvalue != DRAW && bestvalue != WIN))
							{
								if(bestDtmLoss < dtmValue)
									bestDtmLoss = dtmValue;
							}
						}

						// for suicide checkers change next line to bestvalue = WIN
						if(n == 0)
							bestvalue = LOSS;

						dtmValue = bestvalue == LOSS ? bestDtmLoss : bestDtmWin;

						if(n == 0)
							dtmValue = 0;


						// set value in case it's a win or if all successors are known:
						if(conv == n && bestvalue == LOSS)
						{
							SetDatabaseValue(currentdb, i, LOSS);
							// SetDTMValue(dtm, i, 0);
							SetDTMValue(dtm, i, dtmValue + 1);
						}			
						else if(bestvalue != LOSS)
						{
							SetDatabaseValue(currentdb, i, bestvalue);
							// SetDTMValue(dtm, i, 0);
							SetDTMValue(dtm, i, dtmValue + 1);
						}
					}
					IS_MEMORY_PANIC()
					{
						#pragma omp atomic
						countThreadSleep++;
						#pragma omp flush(countThreadSleep)
				
						omp_set_lock(&lockMemoryPanic);
						omp_unset_lock(&lockMemoryPanic);
					}
				}
			}

			delete[] bitMoves;
		}

		TERMINATE_RAISE_EXCEPTION();
	} 


	 // PropagateWhite - passing on moves that do not cause conversion
	////////////////////////////////////////////////////////////////////////////////////////////////

	template<typename BB, int MaxField, int BitsPerRow> 
	int PropagateWhite(uint32 *currentdb_w,uint8* dtm, int wm, int wk, int bm, int bk, int wmrank, int bmrank)
	{
		uint32 j,n;
		int oldvalue;
		uint8 oldDTM;
		int bestvalue;
		int value;
		int64 dbsize = GetDatabaseSize<BitsPerRow, MaxField>(wm, wk, bm, bk, wmrank, bmrank);
		int64 i;
		BB p;
		int done = 1;
		bool symmetric = IsSymmetric(wm, wk, bm, bk, wmrank, bmrank);

		PROGRESS_DECLARE();
		PROGRESS_INIT(5, dbsize);
		DECLARE_TERMINATE_PARALLEL();


		int64 nodes = 0;
	
		#pragma omp parallel default(none) shared(DECLARE_MEMORY_PANIC(), dbsize, wm, wk, bm, bk, wmrank, bmrank, currentdb_w, dtm, done, PROGRESS_PARALLEL(), nodes, TERMINATE_PARALLEL()) private(bestvalue, value, i, p, n, j, oldvalue, oldDTM)
		{
			BB *bitMoves = new BB[MAX_MOVES];

			#pragma omp for schedule(dynamic, 1000)
			for(i=0; i<dbsize; i++)
			{
				#pragma omp flush (TERMINATE_PARALLEL())
				IS_NOT_TERMINATE()
				{
					if( (nodes & 0x3FF) == 0)
					{
						CHECK_TERMINATE_PARALLEL();
						#pragma omp flush (TERMINATE_PARALLEL())
					}

					#pragma omp atomic
					nodes++;
					PROGRESS_CHECK(nodes)
					{
						#pragma omp critical
						{
							PROGRESS_WORK(nodes);
						}
					}

					oldvalue = GetDatabaseValue(currentdb_w, i);
					oldDTM = GetDTMValue(dtm, i);

					IndexToBitBoardXX<BB>(i, &p, wm, wk, bm, bk, wmrank, bmrank);

					// collision detection
					if(p.bm & p.wm)
						continue;
		
					if(oldvalue == UNKNOWN || oldvalue == DRAW)  
					{
						if(TestJump<BB>(g_ED, &p, true))
							continue;

						n = MoveGenerator<BB>(g_ED, &p, true, bitMoves);
		
						// look up all successors and propagate their values
						bestvalue = LOSS;

						uint8 bestDtmWin = 255;
						uint8 bestDtmLoss = 0;
						uint8 dtmValue = 0;
						int drawCount = 0;

						for(j=0; j<n; j++)
						{
							BB resP;

							ToggleMove<BB>(&p, &bitMoves[j]);
							resP = p;
							ToggleMove<BB>(&p, &bitMoves[j]);


							// if this move takes us into another database, don't look up because we did this 
							// in IOpass() if conversion continue
							if(resP.wm)
							{
								if (MSBxx<BB>(resP.wm) / BitsPerRow > wmrank)
									continue;
							}
							if(BitCountXX<BB>(resP.wk) > BitCountXX<BB>(p.wk))
								continue;

							value = Lookup<BB, MaxField, BitsPerRow, true>(&resP, BLACK, &dtmValue);
							//uint8 dtmVal;
							//int64 index;
							//if(dtm_B != NULL)
							//{
							//	BitBoardToIndex(&resP, &index);
							//	dtmVal = GetDTMValue(dtm_B, index);
							//	assert(dtmVal == dtmValue);
							//}

				
							// if we find a successor which is a loss, we have a win and can stop
							if(value == LOSS)
							{
								if(bestvalue == UNKNOWN || bestvalue == DRAW)
									bestDtmWin = dtmValue;
								bestvalue = WIN;
								if(dtmValue >= 50)
								{
									int kkk = 0;
								}
								if(bestDtmWin > dtmValue)
									bestDtmWin = dtmValue;
								break;
							}

							if(value == UNKNOWN && bestvalue != WIN)
							{
								bestDtmWin = 0;
								bestvalue=UNKNOWN;
							}
							if(bestvalue == LOSS && value==DRAW)
							{
								bestvalue = DRAW;
								bestDtmWin = 70;
								drawCount++;
							}
							if(value == WIN && (bestvalue != DRAW && bestvalue != WIN && bestvalue != UNKNOWN))
							{
								if(bestDtmLoss < dtmValue)
									bestDtmLoss = dtmValue;
							}

						} // for

						//if(bestvalue == DRAW)
						//	if(n != drawCount)
						//		bestvalue = UNKNOWN;


						dtmValue = bestvalue == LOSS ? bestDtmLoss : bestDtmWin;

						if(bestvalue == DRAW)
							dtmValue = 0;
						if(n == 0)
							dtmValue = 0;


						if(oldvalue == DRAW)
						// there is a conversion move leading to a draw - can we improve?
						{
							if(bestvalue == WIN)
							{
								SetDatabaseValue(currentdb_w, i, bestvalue);
								SetDTMValue(dtm, i, dtmValue + 1);
								#pragma omp critical
								done = 0;
							}
						}
						else // this means: oldvalue UNKNOWN
						{
							//-----------------------------------------------------------------------------------------------------
							// there is either no conversion move, or only such which lead to a loss.
							// problem with DRAW: if one successor is marked as a draw, but is a loss 
							// (because it is a BitBoard where a conversion will lead to a draw), and
							// all other BitBoards are LOSSES, then this will give bestvalue = draw. 
							// when in fact we don't know it.
							//-----------------------------------------------------------------------------------------------------
				
							// if any successor value was unknown, so will bestvalue be - except if there was a win.
							if(bestvalue == WIN)
							{
								SetDatabaseValue(currentdb_w, i, bestvalue);
								SetDTMValue(dtm, i, dtmValue + 1);
								#pragma omp critical
								done = 0;
							}
							else if(bestvalue == LOSS)
							{
								SetDatabaseValue(currentdb_w, i, bestvalue);
								SetDTMValue(dtm, i, dtmValue + 1);
								#pragma omp critical
								done=0;
							}
						}	
					}
					else
					{
						if(TestJump<BB>(g_ED, &p, true))
							continue;

						n = MoveGenerator<BB>(g_ED, &p, true, bitMoves);
			
						// look up all successors and propagate their values
						uint8 bestDtmWin = 255;
						uint8 bestDtmLoss = 0;
						uint8 dtmValue2 = 0;

						for(j=0; j<n; j++)
						{
							BB resP;

							ToggleMove<BB>(&p, &bitMoves[j]);
							resP = p;
							ToggleMove<BB>(&p, &bitMoves[j]);


							// if this move takes us into another database, don't look up because we did this 
							// in IOpass() if conversion continue
							//conversion = 0;
							//if(resP.wm)
							//{
							//	if (MSBxx<BB>(resP.wm) / BitsPerRow > wmrank)
							//		continue;
							//}
							//if(BitCountXX<BB>(resP.wk) > BitCountXX<BB>(p.wk))
							//	continue;


							value = Lookup<BB, MaxField, BitsPerRow, true>(&resP, BLACK, &dtmValue2);
							//if(value == UNKNOWN)
							//	break;
				
							// if we find a successor which is a loss, we have a win and can stop
							if( value == LOSS && oldvalue == WIN)
							{
								if(bestDtmWin > dtmValue2)
									bestDtmWin = dtmValue2;
							}
							else if(value == WIN && oldvalue == LOSS)
							{
								if(bestDtmLoss < dtmValue2)
									bestDtmLoss = dtmValue2;
							}
						} // for

						//if(value != UNKNOWN)
						{
							dtmValue2 = oldvalue == LOSS ? bestDtmLoss : bestDtmWin;

							if(oldvalue == WIN)
							{
								if(dtmValue2 + 1 != oldDTM)
								{
									SetDTMValue(dtm, i, dtmValue2 + 1);
									#pragma omp critical
									done = 0;
								}
							}
							else if(oldvalue == LOSS)
							{
								if(dtmValue2 + 1 != oldDTM)
								{
									SetDTMValue(dtm, i, dtmValue2 + 1);
									#pragma omp critical
									done = 0;
								}
							}
						}
					}			
					IS_MEMORY_PANIC()
					{
						#pragma omp atomic
						countThreadSleep++;
						#pragma omp flush(countThreadSleep)
				
						omp_set_lock(&lockMemoryPanic);
						omp_unset_lock(&lockMemoryPanic);
					}
				}
			}

			delete[] bitMoves;
		} // pragma parallel

		TERMINATE_RAISE_EXCEPTION();

		return done;
	}


	 // PropagateBlack - passing on moves that do not cause conversion
	////////////////////////////////////////////////////////////////////////////////////////////////

	template<typename BB, int MaxField, int BitsPerRow> 
	int PropagateBlack(uint32 *currentdb_b, uint8* dtm, int wm, int wk, int bm, int bk, int wmrank, int bmrank)
	{
		uint32 j,n;
		int oldvalue;
		uint8 oldDTM;
		int bestvalue;
		int value;
		int64 dbsize = GetDatabaseSize<BitsPerRow, MaxField>(wm, wk, bm, bk, wmrank, bmrank);
		int64 i;
		BB p;
		int done = 1;
		bool symmetric = IsSymmetric(wm, wk, bm, bk, wmrank, bmrank);


		PROGRESS_DECLARE();
		PROGRESS_INIT(5, dbsize);
		DECLARE_TERMINATE_PARALLEL();

		int64 nodes = 0;
	
		#pragma omp parallel default(none) shared(DECLARE_MEMORY_PANIC(), dbsize, wm, wk, bm, bk, wmrank, bmrank, currentdb_b, dtm, done, PROGRESS_PARALLEL(), TERMINATE_PARALLEL(), nodes) private(bestvalue, value, i, p, n, j, oldvalue, oldDTM)
		{
			BB *bitMoves = new BB[MAX_MOVES];

			#pragma omp for schedule(dynamic, 1000)
			for(i=0; i<dbsize; i++)
			{
				#pragma omp flush (TERMINATE_PARALLEL())
				IS_NOT_TERMINATE()
				{

					if( (nodes & 0x3FF) == 0)
					{
						CHECK_TERMINATE_PARALLEL();
						#pragma omp flush (TERMINATE_PARALLEL())
					}

					#pragma omp atomic
					nodes++;
					PROGRESS_CHECK(nodes)
					{
						#pragma omp critical
						{
							PROGRESS_WORK(nodes);
						}
					}

					oldvalue = GetDatabaseValue(currentdb_b, i);
					oldDTM = GetDTMValue(dtm, i);

					IndexToBitBoardXX<BB>(i, &p, wm, wk, bm, bk, wmrank, bmrank);

					// collision detection
					if(p.bm & p.wm)
						continue;

					if(oldvalue == UNKNOWN || oldvalue == DRAW)
					{

						if(TestJump<BB>(g_ED, &p, false))
							continue;



						n = MoveGenerator<BB>(g_ED, &p, false, bitMoves);

						bestvalue = LOSS;

						// look up all successors and propagate their values
						uint8 bestDtmWin = 255;
						uint8 bestDtmLoss = 0;
						uint8 dtmValue = 0;
						int drawCount = 0;

						for(j=0; j<n; j++)
						{
							BB resP;

							ToggleMove<BB>(&p, &bitMoves[j]);
							resP = p;
							ToggleMove<BB>(&p, &bitMoves[j]);

							if(resP.bm)
							{
								if( (MaxField - LSBxx<BB>(resP.bm)) / BitsPerRow > bmrank)
									continue;
							}
							if(BitCountXX<BB>(resP.bk) > BitCountXX<BB>(p.bk))
								continue;

							value = Lookup<BB, MaxField, BitsPerRow, true>(&resP, WHITE, &dtmValue);

							// if we find a successor which is a loss, we have a win and can stop
							if(value == LOSS)
							{
								if(bestvalue == UNKNOWN || bestvalue == DRAW)
									bestDtmWin = dtmValue;
								bestvalue = WIN;
								if(bestDtmWin  > dtmValue)
									bestDtmWin = dtmValue;
								break;
							}

							// else, we just try to improve the best value so far
							// if any of the successor values is UNKNOWN, bestvalue is set to UNKNOWN.
							if(value == UNKNOWN && bestvalue != WIN)
							{
								bestDtmWin = 0;
								bestvalue = UNKNOWN;
							}

							if(bestvalue == LOSS && value==DRAW)
							{
								bestvalue = DRAW;
								bestDtmWin = 70;
								drawCount++;
							}
							if(value == WIN && (bestvalue != DRAW && bestvalue != WIN && bestvalue != UNKNOWN))
							{
								if(bestDtmLoss < dtmValue)
									bestDtmLoss = dtmValue;
							}
						} // for

						//if(bestvalue == DRAW)
						//	if(n != drawCount)
						//		bestvalue =  UNKNOWN;

						dtmValue = bestvalue == LOSS ? bestDtmLoss : bestDtmWin;
						if(bestvalue == DRAW)
							dtmValue = 0;
						if(n == 0)
							dtmValue = 0;
			
						// now, what can we do?
						if(oldvalue == DRAW)
							// there is a conversion move leading to a draw - can we improve?
						{
							if(bestvalue == WIN)
							{
								SetDatabaseValue(currentdb_b, i, bestvalue);
								SetDTMValue(dtm, i, dtmValue + 1);
								#pragma omp critical
								done = 0;
							}
						}
						else // oldvalue UNKNONW
						{
							// there is either no conversion move, or only such which lead to a loss.
							// we cannot set draws. 
							// if any successor value was unknown, so will bestvalue be - except if there was a win.
							if(bestvalue == WIN)
							{
								SetDatabaseValue(currentdb_b, i, bestvalue);
								SetDTMValue(dtm, i, dtmValue + 1);
								#pragma omp critical
								done = 0;
							}
							if(bestvalue == LOSS)
							{
								SetDatabaseValue(currentdb_b, i, bestvalue);
								SetDTMValue(dtm, i, dtmValue + 1);
								#pragma omp critical
								done = 0;
							}
							//if(bestvalue == UNKNOWN)
							//{
							//	SetDatabaseValue(currentdb_b, i, bestvalue);
							//	SetDTMValue(dtm, i, 0);
							//	done = 0;
							//}
						}
					}
					else
					{
						if(TestJump<BB>(g_ED, &p, false))
							continue;

						n = MoveGenerator<BB>(g_ED, &p, false, bitMoves);

						// look up all successors and propagate their values
						uint8 bestDtmWin = 255;
						uint8 bestDtmLoss = 0;
						uint8 dtmValue = 0;

						for(j=0; j<n; j++)
						{
							BB resP;

							ToggleMove<BB>(&p, &bitMoves[j]);
							resP = p;
							ToggleMove<BB>(&p, &bitMoves[j]);

							//if(resP.bm)
							//{
							//	if( (MaxField - LSBxx<BB>(resP.bm)) / BitsPerRow > bmrank)
							//		continue;
							//}
							//if(BitCountXX<BB>(resP.bk) > BitCountXX<BB>(p.bk))
							//	continue;


							value = Lookup<BB, MaxField, BitsPerRow, true>(&resP, WHITE, &dtmValue);
							//if(value == UNKNOWN)
							//	break;

							// if we find a successor which is a loss, we have a win and can stop
							// if we find a successor which is a loss, we have a win and can stop
							if( value == LOSS && oldvalue == WIN)
							{
								if(bestDtmWin > dtmValue)
									bestDtmWin = dtmValue;
							}
							else if(value == WIN && oldvalue == LOSS)
							{
								if(bestDtmLoss < dtmValue)
									bestDtmLoss = dtmValue;
							}
						} // for

						//if(value != UNKNOWN)
						{
							dtmValue = oldvalue == LOSS ? bestDtmLoss : bestDtmWin;

							if(oldvalue == WIN)
							{
								if(dtmValue + 1 != oldDTM)
								{
									SetDTMValue(dtm, i, dtmValue + 1);
									#pragma omp critical
									done = 0;
								}
							}
							else if(oldvalue == LOSS)
							{
								if(dtmValue + 1 != oldDTM)
								{
									SetDTMValue(dtm, i, dtmValue + 1);
									#pragma omp critical
									done = 0;
								}
							}
						}
					}
					IS_MEMORY_PANIC()
					{
						#pragma omp atomic
						countThreadSleep++;
						#pragma omp flush(countThreadSleep)
				
						omp_set_lock(&lockMemoryPanic);
						omp_unset_lock(&lockMemoryPanic);
					}
				}
			}

			delete[] bitMoves;
		}

		TERMINATE_RAISE_EXCEPTION();

		return done;
	}
}